package com.bruce.tool.pay.wechat.wap.back;

import com.alibaba.fastjson.JSON;
import com.bruce.tool.common.arithmetic.MD5;
import com.bruce.tool.common.exception.BaseRuntimeException;
import com.bruce.tool.common.exception.ErrorCode;
import com.bruce.tool.common.util.string.MapHandler;
import com.bruce.tool.common.util.string.XmlUtils;
import com.bruce.tool.pay.wechat.enums.WxPayTradeStatus;
import com.bruce.tool.pay.wechat.qrcode.WXPayUtil;
import com.bruce.tool.pay.wechat.sign.WxPaySignUtil;
import com.bruce.tool.pay.wechat.wap.to.WapOrderWxTo;
import com.bruce.tool.pay.wechat.wap.to.WapOrderWxVo;
import com.bruce.tool.pay.wechat.wap.to.WapPayWxTo;
import com.bruce.tool.pay.wechat.wap.to.WapPayWxVo;
import com.bruce.tool.rpc.http.core.Https;
import com.bruce.tool.rpc.http.handler.sign.SignInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.CollectionUtils;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * @author Bruce(刘正航)
 */
@Slf4j
public class WxWapPayHelper {

    private static String wx_notify_url = "http://118.31.77.86:18181/payment/payCallback";
    private static String wx_order_url = "https://api.mch.weixin.qq.com/pay/orderquery";
    private static String wx_app_key = "kuaigongwangluo91330110ma27wwbf1";
    private static String wx_pay_secret = "d7da7e5ba5c9faf9f3d8ee87e7994d27";
    private static String appid = "wx8dd9d756d12032a3";
    private static String mchid = "1490727912";

    public static void init(String appId, String mchId, String appKey, String appSecret, String notifyUrl) {
        appid = appId;
        mchid = mchId;
        wx_app_key = appKey;
        wx_pay_secret = appSecret;
        wx_notify_url = notifyUrl;
    }

    /**
     * 微信统一下单接口
     * wiki: https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_20&index=1
     */
    public static WapPayWxVo joinAndPrePay(WapPayWxTo wapPayWxTo, String ipAddress) {
        MapHandler params = MapHandler.build()
                .add("body", wapPayWxTo.getSubject())
                .add("out_trade_no", wapPayWxTo.getOrderNo())
                .add("total_fee", wapPayWxTo.getTotalAmount())
                .add("nonce_str", WXPayUtil.generateNonceStr())
                .add("spbill_create_ip", ipAddress)
                .add("notify_url", wx_notify_url)
                .add("trade_type", "MWEB")
                .add("fee_type", "CNY")
                .add("appid", appid)
                .add("mch_id", mchid);
        if (StringUtils.isNotBlank(wapPayWxTo.getRedirectUrl())) {
            params.add("redirect_url", wapPayWxTo.getRedirectUrl());
        }
        if (StringUtils.isNotBlank(wapPayWxTo.getPassbackParams())) {
            params.add("attach", Https.urlEncode(wapPayWxTo.getPassbackParams()));
        }
        SortedMap<String, Object> sortedMap = new TreeMap<>(params);
        // 微信统一支付接口
        String payResult = Https.create().url("https://api.mch.weixin.qq.com/pay/unifiedorder")
                .addAllBodys(sortedMap)
                .signature(new SignInfo(wx_app_key, wx_pay_secret, ""), (signInfo, requestInfo) -> {
                    String signature = WxPaySignUtil.signature(wx_app_key, requestInfo.getBodyParams());
                    requestInfo.getBodyParams().put("sign", signature);
                })
                .print(true)
                .postXml();
        if (Objects.isNull(payResult)) {
            return new WapPayWxVo();
        }
        Map<String, Object> map = XmlUtils.toMap(payResult, StandardCharsets.UTF_8.displayName());
        if (CollectionUtils.isEmpty(map)) {
            return new WapPayWxVo();
        }
        map.put("timestamp", System.currentTimeMillis() / 1000);
        String signature = WxPaySignUtil.signature(wx_app_key, map);
        map.put("spbill_create_ip", ipAddress);
        map.put("sign", signature);
        return JSON.parseObject(JSON.toJSONString(map), WapPayWxVo.class);
    }

    /**
     * 获取订单详情
     * wiki: https://pay.weixin.qq.com/wiki/doc/api/H5.php?chapter=9_2&index=2
     */
    public static WapOrderWxVo wapOrderInfo(WapOrderWxTo wapOrderWxTo) {
        MapHandler params = MapHandler.build()
                .add("appid", appid)
                .add("mch_id", mchid)
                .add("nonce_str", WXPayUtil.generateNonceStr())
                .add("out_trade_no", wapOrderWxTo.getOrderNo());
        SortedMap<String, Object> sortedMap = new TreeMap<>(params);
        String payResult = Https.create().url(wx_order_url)
                .addAllBodys(sortedMap)
                .signature(new SignInfo(wx_app_key, wx_pay_secret, ""), (signInfo, requestInfo) -> {
                    String sortParams = Https.sortParams(requestInfo.getBodyParams());
                    sortParams += "&key=" + wx_app_key;
                    String sign = MD5.encode(sortParams, MD5.Case.UPPER);
                    requestInfo.getBodyParams().put("sign", sign);
                })
                .print(true)
                .postXml();
        Map<String, Object> map = XmlUtils.toMap(payResult, StandardCharsets.UTF_8.displayName());
        String sign = (String) map.get("sign");
        map.remove("sign");
        String signature = WxPaySignUtil.signature(wx_app_key, map);
        if (!sign.equalsIgnoreCase(signature)) {
            log.error("结果验签失败,做日志记录{}", JSON.toJSONString(payResult));
        }
        WapOrderWxVo wapOrderWxVo = JSON.parseObject(JSON.toJSONString(map), WapOrderWxVo.class);
        if (Objects.isNull(wapOrderWxVo.getTradeState())) {
            throw new BaseRuntimeException(ErrorCode.SYSTEM_ERROR, "支付宝订单状态:" + wapOrderWxVo.getReturnMsg());
        }
        WxPayTradeStatus tradeStatus = WxPayTradeStatus.valueOf(wapOrderWxVo.getTradeState());
        if (!WxPayTradeStatus.SUCCESS.equals(tradeStatus)) {
            throw new BaseRuntimeException(ErrorCode.SYSTEM_ERROR, "支付宝订单状态:" + tradeStatus.getValue());
        }
        return wapOrderWxVo;
    }

    public static void main(String[] args) {
        WxWapPayHelper.init("", "", "", "", "");
        WapPayWxTo wx = JSON.parseObject("{\n" +
                "\t\"body\":\"测试支付宝-网页支付\",\n" +
                "\t\"total_fee\":\"1\",\n" +
                "\t\"out_trade_no\":\"12809328138\",\n" +
                "\t\"attach\":\"a%3D1%26b%3D2\"\n" +
                "}", WapPayWxTo.class);
        System.out.println(WxWapPayHelper.joinAndPrePay(wx, ""));
    }

}
